﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Zj.DDDSample.Domain.Events;

namespace Zj.DDDSample.Messaging.Simple
{
    public class SimpleEventBus
        : IEventBus
    {
        #region Ctor.
        public SimpleEventBus(IEnumerable<IEventHandler> handlers)
        {
            this._handlers = handlers;
        }
        #endregion

        #region Private fields.
        private readonly MessageQueue _queue = new MessageQueue();
        private readonly IEnumerable<IEventHandler> _handlers; 
        #endregion

        public async Task PublishAsync<TEvent>(TEvent @event, CancellationToken cancellationToken = default(CancellationToken))
            where TEvent : IEvent
        {
            await Task.Factory.StartNew(() =>
           {
               this._queue.Push(@event);
           });
        }

        public void Subscribe()
        {
            _queue.eventPushed += MessageQueue_EventPushed;
        }

        private void MessageQueue_EventPushed(object sender, EventProcessedArgs e)
        {
            this._handlers.Where(eh => eh.CanHandle(e.Event))
                .ToList()
                .ForEach(eh => Task.Factory.StartNew(() =>
                {
                    eh.HandleAsync(e.Event);
                }));
        }

        #region IDisposable Support
        private bool disposedValue = false; // 要检测冗余调用

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    this.Dispose();
                }

                // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // TODO: 将大型字段设置为 null。

                disposedValue = true;
            }
        }

        // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
        // ~SimpleEventBus() {
        //   // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
        //   Dispose(false);
        // }

        // 添加此代码以正确实现可处置模式。
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
            // TODO: 如果在以上内容中替代了终结器，则取消注释以下行。
            // GC.SuppressFinalize(this);
        }
        #endregion
    }
}
